﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace Kokomo.Mirror.CliMetadata
{
	public static class CliReflector
	{
		public static Type Reflect(this Type type)
		{
			if (type is CliType)
				return ((CliType)type).Reflect();
			else
				return type;
		}

		public static object Reflect(this CustomAttributeData attributeData)
		{
			ConstructorInfo constructor = attributeData.Constructor.Reflect();
			object[] arguments = attributeData.ConstructorArguments.Select(a => a.Value).ToArray();

			object attribute = constructor.Invoke(arguments);
			Type attributeType = constructor.DeclaringType;
			foreach (var namedArg in attributeData.NamedArguments)
			{
				MemberInfo member = namedArg.MemberInfo.Reflect();
				if (member is FieldInfo)
					((FieldInfo)member).SetValue(attribute, namedArg.TypedValue.Value);
				else if (member is PropertyInfo)
					((PropertyInfo)member).SetValue(attribute, namedArg.TypedValue.Value, null);
			}

			return attribute;
		}

		public static Assembly Reflect(this Assembly assembly)
		{
			if (assembly is CliAssembly)
				return ((CliAssembly)assembly).Reflect();
			else
				return assembly;
		}

		public static ConstructorInfo Reflect(this ConstructorInfo constructor)
		{
			if (constructor is CliConstructorInfo)
				return ((CliConstructorInfo)constructor).Reflect();
			else
				return constructor;
		}

		public static MemberInfo Reflect(this MemberInfo member)
		{
			if (member is CliType)
				return ((CliType)member).Reflect();
			else if (member is CliConstructorInfo)
				return ((CliConstructorInfo)member).Reflect();
			else if (member is CliPropertyInfo)
				return ((CliPropertyInfo)member).Reflect();
			else if (member is CliFieldInfo)
				return ((CliFieldInfo)member).Reflect();
			else if (member is CliMethodInfo)
				return ((CliMethodInfo)member).Reflect();
			else if (member is CliEventInfo)
				return ((CliEventInfo)member).Reflect();
			else
				return member;
		}
	}
}
